/*
 * Compiler Construction - Project 1
 *
 * Author : Rakesh Sugirtharaj
 *
 * e-mail : rxs104020@utdallas.edu
 *
 */
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#include<map>

using namespace std;


//global variables
vector<vector<string> > dfa_array; 
vector<char> chars_in_language; // the allowed characters in the language. this is the first row (or header) of the DFA file.
vector<string> states;

string current_state = "";
map<string, string> final_states; //'final state : token name' pair

/* initialize by reading the DFA file into a 2D array */
int initialize(string filename){
	ifstream dfa_file("input.dfa");
	string line;
	
	int line_no = 1;		
	int i = 0;
	if(dfa_file.is_open()){
		while(dfa_file.good()){
			getline(dfa_file,line);
			//cout << "DEBUG :: " << line << endl;
			
			char p[line.size() + 1];//have to create a char array since strtok works only with char arrays.
			p[line.size()] = 0; //last character is a null.
			memcpy(p, line.c_str(),line.size());

			
			int j = 0;
			vector<string> row;
			char *tokens;
			tokens = strtok(p, " ");
			while(tokens!=NULL){
				if(i == 0){ //store the first row as chars in language
					chars_in_language.push_back(tokens[0]);	
				}else if(j == 0){ //store first column as states
					states.push_back(tokens);
				}else if(chars_in_language.size()-1 == j){
					if(tokens[0] != '-'){
					//cout << states[i-1] << " " << tokens << endl;
					final_states.insert(pair<string, string>(states[i-1],tokens));
					}
				}
				else{ //the rest forms the transition table
					row.push_back(tokens);
				}
				
				tokens = strtok(NULL, " ");
				j++;
			}	
			if(row.size() != 0){
				dfa_array.push_back(row);
			}
			i++;
		}
		//cout << final_states.size() << endl;
		//cout << dfa_array.size()<<endl;
		//cout << chars_in_language.size() <<endl;
		dfa_file.close();
	
		}		
	else{
		cout<<"ERROR :: UNABLE TO OPEN DFA FILE"<<endl;
	}
	return 0;
}

//returns the index of an element in the array
int get_index_array(char ch){
	int i;
	for(i=0; i < chars_in_language.size(); i++){
		if(chars_in_language[i] == ch){
			return i;
		}
	}
	return -1;
}

int get_index_string(string state){
	int i;
	for(i=0; i < states.size(); i++){
		if(states[i].compare(state) == 0){
			return i;
		}
	}	
	return -1;
}

string replace_all_spaces(string str){
//remove all spaces
	int pos = str.find(" ");
	while(pos != string :: npos){
		str.replace(pos, 1, "");
		pos = str.find(" ", pos);
	}
//remove all tabs
	pos = str.find("\t");
	while(pos != string :: npos){
		str.replace(pos, 1, "");
		pos = str.find("\t", pos);
	}
	return str;
}

int is_final_state(string st){
	int flag = 0;
	map<string, string> :: iterator it;
	for(it = final_states.begin(); it != final_states.end(); it++){
		if(st.compare(it->first) == 0){
			flag = 1;
		}
	}
	return flag;
}

void identify_token(string str, string token){

	map<string, string> :: iterator it;
	it = final_states.find(token);
	cout << str << " is identified as " << it ->second <<endl;

}

int main(int argc, char* argv[]){
	//initialize the dfa - load table to memory.
	initialize("input.dfa");

	ifstream input_file(argv[2]);
	string str;
	string line;
	string start_state = states[0];
	current_state = start_state;
	if(input_file.is_open()){
		while(input_file.good()){
			getline(input_file, line);
			line = replace_all_spaces(line);
			str.append(line);
		}
	}	
	int i;
	int st_index;
	int char_index;
	int trans_error = 0;
	string new_state = "";


	for(i=0 ; i < str.length(); i++){
		char_index = get_index_array(str[i]);

		if(char_index == -1){
			cout << "ERROR : Invalid input string" << endl;
			exit(0);
		}

		
		st_index = get_index_string(current_state);
		new_state = dfa_array[st_index][char_index-1];

		if(new_state.compare(start_state) == 0){
			identify_token(str.substr(0,i), current_state);
			str = str.substr(i+1);
			i = -1;
			current_state = new_state;
			continue;
		}

		if(get_index_string(new_state) == -1){
			if(is_final_state(current_state)){
				
				identify_token(str.substr(0,i), current_state);
				current_state = start_state;
				str = str.substr(i);
				i = -1;
				continue;
			}else{
				cout << "ERROR : No valid transitions for this string" << endl;
				exit(0);
			}
		}

		current_state = new_state; 
		}
	

	
	return 0;
}
